package com.sinog.biz.schedule;

import com.sinog.biz.mapper.havexml.other.IdNumEncryptMapper;
import com.sinog.biz.util.smlib.Sm4;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @desc 定时任务：给数据库中所有包含身份证信息的表中没有加密的身份证号加密
 * @author jby
 * @date 2022-09-09 9:19
 */
@Slf4j
@Component
@Configuration
@ConditionalOnProperty(name = "gkzx.azbj.sfzjm.open", havingValue = "true")
public class IdNumEncrypt{

    @Autowired
    IdNumEncryptMapper idNumEncryptMapper;

    /**
     * 定时任务：给数据库中所有包含身份证信息的表中没有加密的身份证号加密
     */
    @Scheduled(cron = "${gkzx.azbj.sfzjm.cron}")
    public void idNumEncrypt() {
        log.info("身份证加密处理开始。。。。。。");
        //1.反射分别获取mapper中所有的select方法和update方法，并分别存到2个数组中
        Class<? extends IdNumEncryptMapper> idNumEncryptMapperClass = idNumEncryptMapper.getClass();
        Method[] methods = idNumEncryptMapperClass.getMethods();
        List<Method> selectMethods = new ArrayList<>();
        List<Method> updateMethods = new ArrayList<>();
        for(Method method : methods) {
            String name = method.getName();
            if(name.contains("select")) {
                selectMethods.add(method);
            }
            if(name.contains("update")) {
                updateMethods.add(method);
            }
        }
        //2.然后依次执行每一对对应的select和update方法（因为这样才能让读和写操作的都是同一张表）
        for (int i = 0; i < selectMethods.size(); i++ ){
            try {
                //执行select方法，获取所有身份证号没有加密的记录
                List<Map<String,Object>> list = (List<Map<String, Object>>) selectMethods.get(i).invoke(idNumEncryptMapper);
                if(list.size()>0){
                    //当前表中有需要加密的数据才执行
                    //根据方法名(后2位)找到当前select方法对应的update方法
                    String selectName = selectMethods.get(i).getName();
                    String index = selectName.substring(selectName.length()-2);
                    //遍历所有的update方法，找到方法名中有index的方法，这个方法就是当前select方法对应的update方法
                    Method updateMethod = null;
                    for(Method updateMethod1 : updateMethods) {
                        String name = updateMethod1.getName();
                        if(name.contains(index)) {
                            updateMethod = updateMethod1;
                            break;
                        }
                    }
                    //2，遍历 给从当前select方法（当前表）中拿到的每条数据的idnum加密，然后更新每一条数据的idnum
                    for (Map<String, Object> map : list) {
                        map.put("idNum", Sm4.encryptEcb((String) map.get("idNum")));
                        updateMethod.invoke(idNumEncryptMapper,map.get("idNum"), map.get("priNum"));
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        log.info("身份证加密处理结束。。。。。。");
    }
}